//
// Created by root on 4/29/17.
//


#include "../runner.h"

#define OP_FRACTION(_op,_a,_b,_c,_d,_e,_f) Cell* arg_x = \
    make_fraction(global_scheme, make_integer(global_scheme, _a), make_integer(global_scheme, _b)); \
    Cell* arg_y = make_fraction(global_scheme, make_integer(global_scheme, _c), make_integer(global_scheme, _d)); \
    Cell* ret = make_fraction(global_scheme, make_integer(global_scheme, _e), make_integer(global_scheme, _f)); \
    Cell* r = fraction_##_op \
    (global_scheme, arg_x, arg_y)

#define OP_FRACTION_R(_op,_a,_b,_c,_d,_e) Cell* arg_x = \
    make_fraction(global_scheme, make_integer(global_scheme, _a), make_integer(global_scheme, _b)); \
    Cell* arg_y = make_fraction(global_scheme, make_integer(global_scheme, _c), make_integer(global_scheme, _d)); \
    Cell* ret = make_integer(global_scheme, _e); \
    Cell* r = fraction_##_op \
    (global_scheme, arg_x, arg_y)

#define TEST_OK  assert_true(eqn(r, ret))

static void test_gcd() {
    assert_int_equal(gcd(11, 25), 1);
    assert_int_equal(gcd(24, 36), 12);
}

/**
 * normal cases for fraction operation
 * */

//fraction_add
static void test_fraction_add() {
    OP_FRACTION(add, 1, 2, 3, 5, 11, 10);
    TEST_OK;
}

//fraction_mul
static void test_fraction_mul() {
    OP_FRACTION(mul, 1, 2, 3, 5, 3, 10);
    TEST_OK;
}

//fraction_sub
static void test_fraction_sub() {
    OP_FRACTION(sub, 1, 2, 3, 5, -1, 10);
    TEST_OK;
}

//fraction_div
static void test_fraction_div() {
    OP_FRACTION(div, 1, 2, 3, 5, 5, 6);
    TEST_OK;
}

/**
 * cases for fraction operation when result type changed
 * */

//fraction_add
static void test_fraction_add_returns_integer() {
    OP_FRACTION_R(add, 1, 2, 1, 2, 1);
    TEST_OK;
}

//fraction_mul
static void test_fraction_mul_returns_integer() {
    OP_FRACTION_R(mul, 2, 3, 3, 2, 1);
    TEST_OK;
}

//fraction_sub
static void test_fraction_sub_returns_integer() {
    OP_FRACTION_R(sub, 3, 2, 1, 2, 1);
    TEST_OK;
}

//fraction_div
static void test_fraction_div_returns_integer() {
    OP_FRACTION_R(div, 2, 3, 2, 3, 1);
    TEST_OK;
}

/**
 * cases for fraction operation when arguments are not fractions
 * */




/**
 * cases for fraction div when divided by zero
 * */


//TODO
int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_gcd),
            /*int_add*/
            cmocka_unit_test(test_fraction_add),
            cmocka_unit_test(test_fraction_add_returns_integer),
            /*int_mul*/
            cmocka_unit_test(test_fraction_mul),
            cmocka_unit_test(test_fraction_mul_returns_integer),
            /*int_sub*/
            cmocka_unit_test(test_fraction_sub),
            cmocka_unit_test(test_fraction_sub_returns_integer),
            /*int_div*/
            cmocka_unit_test(test_fraction_div),
            cmocka_unit_test(test_fraction_div_returns_integer),
            //cmocka_unit_test(test_fraction_div_when_divided_by_zero),
    };
    return cmocka_run_group_tests(tests, setup_scheme, teardown_scheme);
}
